#include <string.h>

#include "kgsl_utils.h"

int kgsl_ctx_create(int fd, uint32_t *ctx_id)
{
	struct kgsl_drawctxt_create req = {
			.flags = 0x00001812,
	};
	int ret;

	ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_CREATE, &req);
	if (ret)
		return ret;

	*ctx_id = req.drawctxt_id;

	return 0;
}

int kgsl_gpu_command_payload(int fd, uint32_t ctx_id, uint64_t gpuaddr, uint32_t cmdsize, uint32_t n, uint32_t target_idx, uint64_t target_cmd, uint32_t target_size) {
    struct kgsl_command_object *cmds;

    struct kgsl_gpu_command req = {
            .context_id = ctx_id,
            .cmdsize = sizeof(struct kgsl_command_object),
            .numcmds = n,
    };
    size_t cmds_size;
    uint32_t i;

    cmds_size = n * sizeof(struct kgsl_command_object);

    cmds = (struct kgsl_command_object *) malloc(cmds_size);

    if (cmds == NULL) {
        return -1;
    }

    memset(cmds, 0, cmds_size);

    for (i = 0; i < n; i++) {
        cmds[i].flags = KGSL_CMDLIST_IB;

        if (i == target_idx) {
            cmds[i].gpuaddr = target_cmd;
            cmds[i].size = target_size;
        }
        else {
            /* the shift here is helpful for debugging failed alignment */
            cmds[i].gpuaddr = gpuaddr + (i << 16);
            cmds[i].size = cmdsize;
        }
    }
    req.cmdlist = (unsigned long) cmds;
    return ioctl(fd, IOCTL_KGSL_GPU_COMMAND, &req);
}

int kgsl_map(int fd, unsigned long addr, size_t len, uint64_t *gpuaddr, int readonly) {
    struct kgsl_map_user_mem req = {
            .len = len,
            .offset = 0,
            .hostptr = addr,
            .memtype = KGSL_USER_MEM_TYPE_ADDR,
//            .flags = KGSL_MEMFLAGS_USE_CPU_MAP,
    };
    if (readonly) {
      req.flags |= KGSL_MEMFLAGS_GPUREADONLY;
    }
    int ret;

    ret = ioctl(fd, IOCTL_KGSL_MAP_USER_MEM, &req);
    if (ret)
        return ret;

    *gpuaddr = req.gpuaddr;

    return 0;
}

